package handler

import (
	"encoding/json"
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/gorilla/websocket"
	"strconv"
	"time"
	"www.bwbdim.com/global"
	"www.bwbdim.com/pkg/rabbitmq"
)

type ChatHandler struct {
}

func NewChatHandler() *ChatHandler {
	return &ChatHandler{}
}

// 聊天服务（提供聊天服务的端，简称服务端）
/*
	客户端1 和服务端建立连接
	客户端2 和服务端建立连接
	服务端  分别保存各个客户端的连接信息

	1. 客户端1  给服务端 发送消息
	2. 服务端接收到消息后  从客户端发送过来的消息提取到 消息要发送的对方客户端信息
	3. 服务端通过对方的客户端信息，找到对方客户端的连接信息
	4， 通过连接信息进行推送消息


	代码实现流程
	1. 创建连接
	2. 建立用户和连接信息的映射关系 并且 保存
	3. 启动收发消息功能（使用协程去实现）
*/

var upgrader = websocket.Upgrader{
	ReadBufferSize:  1024, //读取 缓冲区的 大小为  1024
	WriteBufferSize: 1024, //写入 缓冲区的 大小为  1024
}

func (ch *ChatHandler) ChatIm(c *gin.Context) {
	u, _ := c.Get("user_id")
	uid, _ := strconv.Atoi(u.(string))

	//连接信息  根据http协议升级成WebSocket协议
	conn, err := upgrader.Upgrade(c.Writer, c.Request, nil)
	if err != nil {
		return
	}

	node := global.Node{
		Conn: conn,
		Data: make(chan []byte, 50), //用于接收其他消息，其他消息都是通过这个通道进行传递  发消息协程监听这个通道
	}

	//保存用户的连接信息到全局变量中

	global.ClientMap[uid] = node

	fmt.Println(global.ClientMap)

	go ReadMessage(node)
	go WriteMessage(node)

}

// 收消息协程

func ReadMessage(node global.Node) {
	for {
		//服务端获取客户端发送的消息  如果没有消息，这个函数会阻塞
		_, message, err := node.Conn.ReadMessage()
		if err != nil {
			return
		}

		fmt.Println(string(message))

		var msg global.Message

		json.Unmarshal(message, &msg)

		fmt.Println(msg)

		switch msg.Cmd {
		case 1:

			sendStatus := 1
			//判断对方 的连接信息是否存在ClientMap里面  如果存在则发送消息
			if n, ok := global.ClientMap[msg.DistId]; ok {
				n.Data <- message
			} else {
				sendStatus = 0
			}

			//消息存储 （ 已发送  未发送） 使用RabbitMQ进行消息的异步存储

			RabbitMQ := rabbitmq.NewRabbitMQSimple("im_save_message")
			newMessage := map[string]interface{}{
				"message":    msg,
				"sendStatus": sendStatus,
				"created_at": time.Now().UnixNano(),
			}

			m, _ := json.Marshal(newMessage)

			RabbitMQ.PublishSimple(string(m))

		case 2: //群聊
		default:
			//消息类型错误
		}

	}

}

//发消息协程

func WriteMessage(node global.Node) {
	for {
		data := <-node.Data

		node.Conn.WriteMessage(websocket.TextMessage, data)
	}
}
